﻿
namespace SharePoint.ImportExport.Compression
{
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.IO;
    using System.Xml;
    using System.Xml.Serialization;
    using System.Diagnostics;

    using SharePoint.ImportExport.Core;

    /// <summary>
    /// This is the compressor help class
    /// </summary>
    public class Compressor
    {

        private void CleanUpList(List list, string directory, bool xmlFilesOnly)
        {
            foreach (List folder in list.Folders)
            {
                CleanUpList(folder, directory, xmlFilesOnly);
            }

            if (!File.Exists(directory + list.RelativeitemXML))
            {
                return;
            }

            FileInfo fiItem = new FileInfo(directory + list.RelativeitemXML);

            if (!xmlFilesOnly)
            {
                // A FileStream is needed to read the XML document.
                using (FileStream fsListOfItems = new FileStream(directory + list.RelativeitemXML, FileMode.Open))
                {

                    // Declare an object variable of the type to be deserialized.
                    SharePoint.ImportExport.Core.ListOfItems exportedList = new SharePoint.ImportExport.Core.ListOfItems();

                    using (XmlReader readerOfItems = new XmlTextReader(fsListOfItems))
                    {
                        try
                        {
                            // Create an instance of the XmlSerializer specifying type and namespace.
                            XmlSerializer serializerOfItems = new XmlSerializer(typeof(SharePoint.ImportExport.Core.ListOfItems));
                            // Use the Deserialize method to restore the object's state.
                            exportedList = (SharePoint.ImportExport.Core.ListOfItems)serializerOfItems.Deserialize(readerOfItems);
                            foreach (SharePoint.ImportExport.Core.ItemsOfContentType profile in exportedList.ItemsOfContentType)
                            {
                                foreach (SharePoint.ImportExport.Core.Item item in profile.Items)
                                {
                                    if (item.FileName != null)
                                    {
                                        if (File.Exists(fiItem.DirectoryName + "\\" + item.FileName))
                                        {
                                            string fileName = fiItem.DirectoryName + "\\" + item.FileName;
                                            File.Delete(fileName);
                                        }
                                    }
                                }
                            }


                        }
                        catch (Exception Ex)
                        {
                        }
                        finally
                        {
                            readerOfItems.Close();
                            fsListOfItems.Close();
                        }
                    }
                }
            }

            File.Delete(fiItem.FullName);

        }

        private void CleanUpSite(Site site, string directory, bool xmlFilesOnly)
        {
            foreach (Site subSite in site.SubSites)
            {
                CleanUpSite(subSite, directory, xmlFilesOnly);
            }
            foreach (List list in site.Lists)
            {
                CleanUpList(list, directory, xmlFilesOnly);

            }
            foreach (Page pag in site.DesignElements.Pages)
            {
                try
                {
                    if (!String.IsNullOrEmpty(pag.FileName))
                    {
                        File.Delete(pag.FileName);
                    }
                }
                catch (Exception Ex)
                {
                }
            }
            foreach (Resource res in site.DesignElements.Resources)
            {
                try
                {
                    File.Delete(res.File);
                }
                catch (Exception Ex)
                {
                }
            }

        }


        private void CompressSite(Site site, StreamWriter sw, string packagePath)
        {
            foreach (Page pag in site.DesignElements.Pages)
            {
                if (!String.IsNullOrEmpty(pag.FileName) && File.Exists(packagePath + "\\" + pag.FileName))
                {
                    sw.WriteLine(pag.FileName);
                }
            }

            foreach (List list in site.Lists)
            {
                CompressList(list, sw, packagePath);
            }

            foreach (Site subSite in site.SubSites)
            {
                CompressSite(subSite, sw, packagePath);
            }


        }
        private void CompressList(List list, StreamWriter sw, string packagePath)
        {
            foreach (List folder in list.Folders)
            {
                CompressList(folder, sw, packagePath);
            }

            FileInfo fi = new FileInfo(packagePath + list.RelativeitemXML);
            string s = fi.DirectoryName.Substring(packagePath.Length + 1);
            sw.WriteLine(".Set DestinationDir = \"" + s + "\"");
            sw.WriteLine("\"" + list.RelativeitemXML.Substring(1) + "\"");
            if (!File.Exists(packagePath + list.RelativeitemXML))
            {
                return;
            }

            FileInfo fiItem = new FileInfo(packagePath + list.RelativeitemXML);

            // A FileStream is needed to read the XML document.
            using (FileStream fsListOfItems = new FileStream(packagePath + list.RelativeitemXML, FileMode.Open))
            {

                // Declare an object variable of the type to be deserialized.
                SharePoint.ImportExport.Core.ListOfItems exportedList = new SharePoint.ImportExport.Core.ListOfItems();

                using (XmlReader readerOfItems = new XmlTextReader(fsListOfItems))
                {
                    try
                    {
                        // Create an instance of the XmlSerializer specifying type and namespace.
                        XmlSerializer serializerOfItems = new XmlSerializer(typeof(SharePoint.ImportExport.Core.ListOfItems));
                        // Use the Deserialize method to restore the object's state.
                        exportedList = (SharePoint.ImportExport.Core.ListOfItems)serializerOfItems.Deserialize(readerOfItems);
                        foreach (SharePoint.ImportExport.Core.ItemsOfContentType profile in exportedList.ItemsOfContentType)
                        {
                            foreach (SharePoint.ImportExport.Core.Item item in profile.Items)
                            {
                                if (item.FileName != null)
                                {
                                    if (File.Exists(fi.DirectoryName + "\\" + item.FileName))
                                    {
                                        string fileName = fi.DirectoryName + "\\" + item.FileName;
                                        sw.WriteLine("\"" + fileName.Substring(packagePath.Length + 1) + "\"");
                                    }
                                }
                            }
                        }


                    }
                    catch (Exception Ex)
                    {
                    }
                    finally
                    {
                        readerOfItems.Close();
                        fsListOfItems.Close();
                    }
                }
            }

        }

        /// <summary>
        /// This method extracts the data from the specified package
        /// </summary>
        /// <param name="package">Full Paths to package file</param>
        /// <param name="directory">Directory that the files will be extracted to</param>
        /// <returns></returns>
        public bool Extract(string package, string directory)
        {
            bool returnValue = true;
            FileInfo fi = new FileInfo(package);

            Directory.CreateDirectory(directory);

            Process p = new Process();
            ProcessStartInfo pInfo = new ProcessStartInfo("extrac32.exe");
            pInfo.WorkingDirectory = fi.DirectoryName;
            pInfo.Arguments = "/E /L \"" + directory + "\" \"" + package + "\"";
            pInfo.WindowStyle = ProcessWindowStyle.Hidden;
            p.StartInfo = pInfo;
            p.Start();
            p.WaitForExit();


            return returnValue;
        }

        /// <summary>
        /// This method compresses all files specified in the struct.xml file
        /// </summary>
        /// <param name="structFile">Path and filename of the struct.xml file</param>
        /// <param name="packageFolder">Folder that will contain the packaged data</param>
        /// <returns></returns>
        public bool Compress(string structFile, string packageFolder)
        {
            string packagePath;
            FileInfo fiStruct = new FileInfo(structFile);
            if (!fiStruct.Exists)
            {
                return false;
            }
            else
            {
                packagePath = fiStruct.DirectoryName;
            }

            bool returnValue = true;

            using (StreamWriter sw = new StreamWriter(packagePath + "\\data.ddf", false))
            {
                sw.WriteLine(";*** SharePoint ImportExportData");
                sw.WriteLine(";");
                sw.WriteLine(".OPTION EXPLICIT     ; Generate errors");
                sw.WriteLine(".Set CabinetNameTemplate=Exporteddata.cab");
                sw.WriteLine(".set DiskDirectoryTemplate=CDROM ; All cabinets go in a single directory");
                sw.WriteLine(".Set CompressionType=MSZIP;** All files are compressed in cabinet files");
                sw.WriteLine(".Set UniqueFiles=\"OFF\"");
                sw.WriteLine(".Set Cabinet=on");
                sw.WriteLine(".Set DiskDirectory1=" + packageFolder);
                sw.WriteLine(".Set MaxDiskSize=CDROM	       		; 3.5\" disks");

                Import importdata = new Import();
                //// A FileStream is needed to read the XML document.
                using (FileStream fs = new FileStream(structFile, FileMode.Open))
                {
                    using (XmlReader reader = new XmlTextReader(fs))
                    {
                        // Declare an object variable of the type to be deserialized.
                        // Create an instance of the XmlSerializer specifying type and namespace.
                        XmlSerializer serializer = new XmlSerializer(typeof(Import));

                        try
                        {
                            // Use the Deserialize method to restore the object's state.
                            importdata = (Import)serializer.Deserialize(reader);

                            sw.WriteLine(fs.Name);

                            if (File.Exists(fiStruct.DirectoryName + "\\listtemplates.xml"))
                            {
                                sw.WriteLine("listtemplates.xml");
                            }

                            foreach (Site site in importdata.RootContainers[0].Sites)
                            {
                                CompressSite(site, sw, packagePath);
                            }
                        }

                        catch (InvalidOperationException ex)
                        {
                            Logger.Log(ErrorLevel.Error, "Error loading " + structFile + ": " + ex.Message + "\t" + ex.InnerException.Message);
                        }
                        finally
                        {
                            reader.Close();
                            fs.Close();
                        }
                    }
                }




                sw.WriteLine(";*** <the end>");
                sw.Flush();

            }

            Process p = new Process();
            ProcessStartInfo pInfo = new ProcessStartInfo("makecab.exe");
            pInfo.WorkingDirectory = packagePath;
            pInfo.Arguments = "/f " + packagePath + "\\data.ddf";
            pInfo.WindowStyle = ProcessWindowStyle.Hidden;
            p.StartInfo = pInfo;

            p.Start();
            p.WaitForExit();
            int code = p.ExitCode;
            returnValue = (code == 0);
            File.Delete(packagePath + "\\data.ddf");
            File.Delete(packagePath + "\\setup.inf");
            File.Delete(packagePath + "\\setup.rpt");
            return returnValue;

        }

        /// <summary>
        /// This routine cleans up all files in a specified struct.xml file
        /// </summary>
        /// <param name="structFile">Path to struct.xml file</param>
        /// <param name="xmlFilesOnly">Boolean flag indicating if only the created xml files will be deleted</param>
        /// <returns></returns>
        public bool CleanUp(string structFile, bool xmlFilesOnly)
        {
            FileInfo fiStruct = new FileInfo(structFile);
            if (!fiStruct.Exists)
            {
                return false;
            }
            bool returnValue = false;

            try
            {
                Import importdata = new Import();
                //// A FileStream is needed to read the XML document.
                using (FileStream fs = new FileStream(structFile, FileMode.Open, FileAccess.Read, FileShare.Delete))
                {
                    using (XmlReader reader = new XmlTextReader(fs))
                    {
                        // Declare an object variable of the type to be deserialized.
                        // Create an instance of the XmlSerializer specifying type and namespace.
                        XmlSerializer serializer = new XmlSerializer(typeof(Import));

                        try
                        {
                            // Use the Deserialize method to restore the object's state.
                            importdata = (Import)serializer.Deserialize(reader);

                            File.Delete(structFile);

                            foreach (Site site in importdata.RootContainers[0].Sites)
                            {
                                CleanUpSite(site, fiStruct.DirectoryName, xmlFilesOnly);

                            }
                        }

                        catch (InvalidOperationException ex)
                        {
                            Logger.Log(ErrorLevel.Error, "Error loading " + structFile + ": " + ex.Message + "\t" + ex.InnerException.Message);
                        }
                        finally
                        {
                            reader.Close();
                            fs.Close();
                        }
                    }

                }
            }
            catch (Exception Ex)
            {
            }

            File.Delete(structFile);
            File.Delete(fiStruct.DirectoryName + "\\Listtemplates.xml");

            return returnValue;

        }
    }
}
